package com.ironman.sailboat.mobile.computer.v2;


import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;

/**
 * 1.2
 * 优化计算粒度
 */
public class GeneralTrainData {

    /**
     * 主舵手姓名
     */
    private String mHmName;

    /**
     * 船组颜色
     */
    private String color;

    /**
     * 经度
     */
    private Double longitude;

    /**
     * 纬度
     */
    private Double latitude;

    /**
     * 航向 ° (真北)
     */
    private Integer headingT;

    /**
     * 航向 ° (磁北)
     */
    private Integer headingM;

    /**
     * 航速
     */
    private Double speed;

    /**
     * 标准船速
     */
    private Double standardSpeed;

    /**
     * 自定义标准船速
     */
    private Double customStandardSpeed;

    /**
     * 角度c
     */
    private Integer angle;

    /**
     * VMG
     */
    private Double vmg;

    /**
     * 标准VMG
     */
    private Double standardVmg;

    /**
     * 自定义角度c
     */
    private Integer customAngle;

    /**
     * 自定义风VMG
     */
    private Double customVmg;

    /**
     * 自定义标准VMG
     */
    private Double customStandardVmg;

    /**
     * 风数据来源
     */
    private String windSourceBoatCode;

    /**
     * 平均风速
     */
    private Double windSpeed;

    /**
     * 平均风向
     */
    private Integer windDirection;

    /**
     * 自定义风速
     */
    private Double customWindSpeed;

    /**
     * 自定义风向
     */
    private Integer customWindDirection;

    /**
     * 船首向
     */
    private Integer yaw;

    /**
     * 俯仰角
     */
    private Integer pitch;

    /**
     * 平衡
     */
    private Integer rol;

    /**
     * 舵手心率
     */
    private List<Integer> hr;

    /**
     * 航行状态
     */
    private String sailStatus;

    /**
     * 漂角
     */
    private String leeway;

    /**
     * 航行姿态
     */
    private String posture;

    /**
     * 俯仰姿态
     */
    private String pitchPosture;

    /**
     * 平衡偏离阈值
     */
    private transient final int rolBalanceDeviation;

    /**
     * 俯仰角偏离阈值
     */
    private transient final int pitchBalanceDeviation;

    private transient final Function<Double, double[]> standardUFun;

    private transient final Function<Double, double[]> standardDFun;

    public GeneralTrainData(String mHmName, String color, List<Integer> hr,
                            int rolBalanceDeviation,
                            int pitchBalanceDeviation,
                            Function<Double, double[]> standardUFun, Function<Double, double[]> standardDFun) {
        this.mHmName = mHmName;
        this.color = color;
        this.hr = hr;
        this.rolBalanceDeviation = rolBalanceDeviation;
        this.pitchBalanceDeviation = pitchBalanceDeviation;
        this.standardUFun = standardUFun;
        this.standardDFun = standardDFun;
    }

    public void compute(String dataType) {
        /*
         * 角度和VMG
         * ● | headingM-windDirection | ≤ 180°，angle = | headingM-windDirection |；
         * ● | headingM-windDirection | ＞ 180°，angle= 360° - | headingM-windDirection |；
         * ● vmg=实时船速*COS(angle)
         * 自定义角度和自定义VMG
         * ● | headingM-customWindDirection | ≤ 180°，customAngle = | headingM-customWindDirection |；
         * ● | headingM-customWindDirection | ＞ 180°，customAngle = 360° - | headingM-customWindDirection |；
         * ● customVmg=实时船速*COS(customAngle)
         */
        if ("gps".equals(dataType) || "wind".equals(dataType)) {
            if (Objects.nonNull(headingM) && Objects.nonNull(windDirection)) {
                int a = this.headingM - this.windDirection;

                int absAngle = Math.abs(a);
                this.angle = absAngle <= 180 ? absAngle : 360 - absAngle;
                if (Objects.nonNull(speed)) {
                    this.vmg = BigDecimal.valueOf(speed * Math.cos(Math.toRadians(angle))).setScale(4, RoundingMode.HALF_UP).doubleValue();
                } else {
                    this.vmg = null;
                }

                /*
                 * 航行状态(sailStatus)
                 * A= headingM - windDirection
                 * ● 顺风左舷（D_P）：当 90° ＜ A ≤ 180°，或 -270° ＜ A ＜ -180°；
                 * ● 顺风右舷（D_S）：当 -180° ＜ A＜ -90°，或 180° ＜ A ＜ 270°；
                 * ● 迎风左舷（U_P）：当 0° ≤ A ≤ 90°，或 -360° ＜ A ≤ -270°；
                 * ● 迎风右舷（U_S）：当 270° ≤ A ＜ 360°，或 -90° ≤ A＜ 0°；
                 */
                if ((90 < a && a <= 180) || (-270 < a && a < -180)) {
                    // 顺风左舷
                    this.sailStatus = "D_P";
                } else if ((-180 < a && a < -90) || (180 < a && a < 270)) {
                    // 顺风右舷
                    this.sailStatus = "D_S";
                } else if ((0 <= a && a <= 90) || (-360 < a && a <= -270)) {
                    // 迎风左舷
                    this.sailStatus = "U_P";
                } else if ((270 <= a && a < 360) || (-90 <= a && a < 0)) {
                    // 迎风右舷
                    this.sailStatus = "U_S";
                } else {
                    this.sailStatus = null;
                }
                if (this.sailStatus != null) {
                    if ("U_S".equals(sailStatus) || "U_P".equals(sailStatus)) {
                        if (Objects.nonNull(windSpeed)) {
                            if (Objects.isNull(this.standardUFun)) {
                                this.standardSpeed = null;
                                this.standardVmg = null;
                            } else {
                                double[] standard = this.standardUFun.apply(windSpeed);
                                this.standardSpeed = standard[0];
                                this.standardVmg = standard[1];
                            }
                        } else {
                            this.standardSpeed = null;
                            this.standardVmg = null;
                        }
                        if (Objects.nonNull(customWindSpeed)) {
                            if (Objects.isNull(this.standardUFun)) {
                                this.customStandardSpeed = null;
                                this.customStandardVmg = null;
                            } else {
                                double[] customStandard = this.standardUFun.apply(customWindSpeed);
                                this.customStandardSpeed = customStandard[0];
                                this.customStandardVmg = customStandard[1];
                            }
                        } else {
                            this.customStandardSpeed = null;
                            this.customStandardVmg = null;
                        }
                    } else {
                        if (Objects.nonNull(windSpeed)) {
                            if (Objects.isNull(this.standardDFun)) {
                                this.standardSpeed = null;
                                this.standardVmg = null;
                            } else {
                                double[] standard = this.standardDFun.apply(windSpeed);
                                this.standardSpeed = standard[0];
                                this.standardVmg = standard[1];
                            }
                        } else {
                            this.standardSpeed = null;
                            this.standardVmg = null;
                        }
                        if (Objects.nonNull(customWindSpeed)) {
                            if (Objects.isNull(this.standardDFun)) {
                                this.customStandardSpeed = null;
                                this.customStandardVmg = null;
                            } else {
                                double[] customStandard = this.standardDFun.apply(customWindSpeed);
                                this.customStandardSpeed = customStandard[0];
                                this.customStandardVmg = customStandard[1];
                            }
                        } else {
                            this.customStandardSpeed = null;
                            this.customStandardVmg = null;
                        }
                    }
                } else {
                    this.standardSpeed = null;
                    this.standardVmg = null;
                    this.customStandardSpeed = null;
                    this.customStandardVmg = null;
                }
            } else {
                this.angle = null;
                this.vmg = null;
                this.sailStatus = null;

                this.standardSpeed = null;
                this.standardVmg = null;
                this.customStandardSpeed = null;
                this.customStandardVmg = null;
            }

            if (Objects.nonNull(headingM) && Objects.nonNull(customWindDirection)) {
                int absCustomAngle = Math.abs(headingM - customWindDirection);
                customAngle = absCustomAngle <= 180 ? absCustomAngle : 360 - absCustomAngle;
                if (Objects.nonNull(speed)) {
                    customVmg = BigDecimal.valueOf(speed * Math.cos(Math.toRadians(customAngle))).setScale(4, RoundingMode.HALF_UP).doubleValue();
                } else {
                    customVmg = null;
                }
            } else {
                customAngle = null;
                customVmg = null;
            }
        }

        /*
         * 姿态(posture)
         * ●  当帆船航行状态为U_S和D_S时，rol绝对值小于等于设定阈值时，则帆船平衡，当小于负设定阈值时帆船反扣，当大于正设定阈值度时则帆船倾斜;
         * ● 当帆船航行状态为U_P和D_P时，rol绝对值小于等于设定阈值时，则帆船平衡，当小于负设定阈值时帆船倾斜，当大于正设定阈值度时则帆船反扣;
         */
        if ("posture".equals(dataType)) {
            if (Objects.nonNull(rol)) {
                if (Math.abs(rol) <= rolBalanceDeviation) {
                    posture = "平衡";
                } else {
                    if (sailStatus == null) {
                        posture = null;
                    } else {
                        if ("U_S".equals(sailStatus) || "D_S".equals(sailStatus)) {
                            if (rol > 0) {
                                posture = "倾斜";
                            } else {
                                posture = "反扣";
                            }
                        } else {
                            if (rol > 0) {
                                posture = "反扣";
                            } else {
                                posture = "倾斜";
                            }
                        }
                    }
                }
            } else {
                posture = null;
            }

            if (Objects.nonNull(pitch)) {
                if (Math.abs(pitch) <= pitchBalanceDeviation) {
                    pitchPosture = "平衡";
                } else {
                    if (pitch > 0) {
                        pitchPosture = "前仰";
                    } else {
                        pitchPosture = "后仰";
                    }
                }
            } else {
                pitchPosture = null;
            }
        }

        /*
         * 漂角(leeway)
         * ● |headingM-yaw|≤90°，w=headingM-yaw;
         * ● headingM-yaw＞90°， w=headingM-yaw-360°;
         * ● headingM-yaw＜-90°，w=360°+headingM-yaw;
         * ● 当姿态为U_P时，如果w>0,  leeway = -w， 如果w<0  leeway = +|w|, 如果w=0，leeway = 0
         * ● 当姿态为U_S时，如果w>0,  leeway = +w，如果w<0  leeway = -|w|, 如果w=0，leeway = 0
         * ● 当姿态为D_P时，如果w>0,  leeway = +w，如果w<0  leeway = -|w|, 如果w=0，leeway = 0
         * ● 当姿态为D_S时，如果w>0,  leeway = +w，如果w<0  leeway = -|w|, 如果w=0，leeway = 0
         */
        if ("posture".equals(dataType) || "gps".equals(dataType)) {
            if (Objects.nonNull(headingM) && Objects.nonNull(yaw)) {
                int e = headingM - yaw;
                int w;
                if (Math.abs(e) <= 90) {
                    w = e;
                } else if (e > 90) {
                    w = e - 360;
                } else {
                    w = 360 + e;
                }
                if (w == 0) {
                    leeway = "0";
                } else {
                    if (sailStatus == null) {
                        leeway = null;
                    } else {
                        if ("U_P".equals(sailStatus)) {
                            leeway = w > 0 ? "-" + w : "+" + Math.abs(w);
                        } else {
                            leeway = w > 0 ? "+" + w : "-" + Math.abs(w);
                        }
                    }
                }
            } else {
                leeway = null;
            }
        }
    }

    public String getmHmName() {
        return mHmName;
    }

    public void setmHmName(String mHmName) {
        this.mHmName = mHmName;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public Double getLongitude() {
        return longitude;
    }

    public void setLongitude(Double longitude) {
        this.longitude = longitude;
    }

    public Double getLatitude() {
        return latitude;
    }

    public void setLatitude(Double latitude) {
        this.latitude = latitude;
    }

    public Integer getHeadingT() {
        return headingT;
    }

    public void setHeadingT(Integer headingT) {
        this.headingT = headingT;
    }

    public Integer getHeadingM() {
        return headingM;
    }

    public void setHeadingM(Integer headingM) {
        this.headingM = headingM;
    }

    public Double getSpeed() {
        return speed;
    }

    public void setSpeed(Double speed) {
        this.speed = speed;
    }

    public Double getStandardSpeed() {
        return standardSpeed;
    }

    public void setStandardSpeed(Double standardSpeed) {
        this.standardSpeed = standardSpeed;
    }

    public Double getCustomStandardSpeed() {
        return customStandardSpeed;
    }

    public void setCustomStandardSpeed(Double customStandardSpeed) {
        this.customStandardSpeed = customStandardSpeed;
    }

    public Integer getAngle() {
        return angle;
    }

    public void setAngle(Integer angle) {
        this.angle = angle;
    }

    public Double getVmg() {
        return vmg;
    }

    public void setVmg(Double vmg) {
        this.vmg = vmg;
    }

    public Double getStandardVmg() {
        return standardVmg;
    }

    public void setStandardVmg(Double standardVmg) {
        this.standardVmg = standardVmg;
    }

    public Integer getCustomAngle() {
        return customAngle;
    }

    public void setCustomAngle(Integer customAngle) {
        this.customAngle = customAngle;
    }

    public Double getCustomVmg() {
        return customVmg;
    }

    public void setCustomVmg(Double customVmg) {
        this.customVmg = customVmg;
    }

    public Double getCustomStandardVmg() {
        return customStandardVmg;
    }

    public void setCustomStandardVmg(Double customStandardVmg) {
        this.customStandardVmg = customStandardVmg;
    }

    public String getWindSourceBoatCode() {
        return windSourceBoatCode;
    }

    public void setWindSourceBoatCode(String windSourceBoatCode) {
        this.windSourceBoatCode = windSourceBoatCode;
    }

    public Double getWindSpeed() {
        return windSpeed;
    }

    public void setWindSpeed(Double windSpeed) {
        this.windSpeed = windSpeed;
    }

    public Integer getWindDirection() {
        return windDirection;
    }

    public void setWindDirection(Integer windDirection) {
        this.windDirection = windDirection;
    }

    public Double getCustomWindSpeed() {
        return customWindSpeed;
    }

    public void setCustomWindSpeed(Double customWindSpeed) {
        this.customWindSpeed = customWindSpeed;
    }

    public Integer getCustomWindDirection() {
        return customWindDirection;
    }

    public void setCustomWindDirection(Integer customWindDirection) {
        this.customWindDirection = customWindDirection;
    }

    public Integer getYaw() {
        return yaw;
    }

    public void setYaw(Integer yaw) {
        this.yaw = yaw;
    }

    public Integer getPitch() {
        return pitch;
    }

    public void setPitch(Integer pitch) {
        this.pitch = pitch;
    }

    public Integer getRol() {
        return rol;
    }

    public void setRol(Integer rol) {
        this.rol = rol;
    }

    public List<Integer> getHr() {
        return hr;
    }

    public void setHr(List<Integer> hr) {
        this.hr = hr;
    }

    public String getSailStatus() {
        return sailStatus;
    }

    public void setSailStatus(String sailStatus) {
        this.sailStatus = sailStatus;
    }

    public String getLeeway() {
        return leeway;
    }

    public void setLeeway(String leeway) {
        this.leeway = leeway;
    }

    public String getPosture() {
        return posture;
    }

    public void setPosture(String posture) {
        this.posture = posture;
    }

    public String getPitchPosture() {
        return pitchPosture;
    }

    public void setPitchPosture(String pitchPosture) {
        this.pitchPosture = pitchPosture;
    }
}
